%option yylineno
%option warn
%{
    #include "common.h"

    #include "syntax.tab.h"

    #include "syntax-tree.h"

    static inline void clear_note(char c1);
    
    //#define DEBUG_ON_FLEX

    #ifdef DEBUG_ON_FLEX
    #define LOG_FLEX_NATIVE(...) printf(__VA_ARGS__)
    #else 
    #define LOG_FLEX_NATIVE(...) (void)(0)
    #endif

    #define LOG_ON_FLEX(fmt,...) LOG_FLEX_NATIVE("FLEX: Line %d, " fmt , yylineno,##__VA_ARGS__)

    #define RET(X) \
    do{\
        yylval.t=treeNodeTokenInit(X,yylineno);yylval.t->info= #X;\
        LOG_ON_FLEX( #X "\n");\
        return X;\
    }while(0)

    #ifdef RELOP_DETAIL
        #define FOR_RELOP(X) \
        do{\
            yylval.t=treeNodeTokenInit(X,yylineno);yylval.t->data.type_int= X ;yylval.t->info="RELOP: " #X ;\
            LOG_ON_FLEX("RELOP\n");return RELOP;\
        }while(0)
    #else
        #define FOR_RELOP(X) \
        do{\
            yylval.t=treeNodeTokenInit(X,yylineno);yylval.t->data.type_int= X ;yylval.t->info="RELOP";\
            LOG_ON_FLEX("RELOP\n");return RELOP;\
        }while(0)
    #endif

    extern int flex_error;

    int yycolumn = 1;
    #define YY_USER_ACTION \
        yylloc.first_line = yylloc.last_line = yylineno; \
        yylloc.first_column = yycolumn;\
        yylloc.last_column = yycolumn + yyleng ; \
        yycolumn += yyleng;
%}

digit [0-9]
digit_0x [0-9a-fA-F]
digit_0 [0-7]
int_10 ([1-9]{digit}*)|0
int_16 0[xX]{digit_0x}+
int_8 0{digit_0}+
float_simple {digit}+\.{digit}+
float_complex (({digit}*\.{digit}+)|({digit}+\.))[eE][+-]?{digit}+
ID [a-zA-Z_][a-zA-Z0-9_]*

%%
[ \r\t] {}
\n {
    yycolumn=1;
}
\/\/ {LOG_ON_FLEX("NOTE: \n//");clear_note('\n');LOG_FLEX_NATIVE("\n");}
\/\* {LOG_ON_FLEX("NOTE: \n/*");clear_note('*');LOG_FLEX_NATIVE("\n");}
; {RET(SEMI);}
, {RET(COMMA);}
>= {FOR_RELOP(GE);}
(<=) {FOR_RELOP(LE);}
(==) {FOR_RELOP(EQ);}
(!=) {FOR_RELOP(NE);}
(>) {FOR_RELOP(GT);}
(<) {FOR_RELOP(LT);}
= {RET(ASSIGNOP);}
\+ {RET(PLUS);}
\- {RET(MINUS);}
\* {RET(STAR);}
\/ {RET(DIV);}
&& {RET(AND);}
\|\| {RET(OR);}
! {RET(NOT);}
\( {RET(LP);}
\) {RET(RP);}
\[ {RET(LB);}
\] {RET(RB);}
\{ {RET(LC);}
\} {RET(RC);}
(int)|(float) {
    yylval.t=treeNodeTokenInit(TYPE,yylineno);
    yylval.t->data.type_int=(yytext[0]=='i'?1:2);
    yylval.t->info=(yytext[0]=='i'?"TYPE: int":"TYPE: float");
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return TYPE;
}
if {RET(IF);}
else {RET(ELSE);}
while {RET(WHILE);}
struct {RET(STRUCT);}
return {RET(RETURN);}

{float_complex}|{float_simple} {
    yylval.t=treeNodeTokenInit(FLOAT,yylineno);
    yylval.t->data.type_float=(float)strtof(yytext,NULL); 
    yylval.t->info=str_maker("FLOAT: %f",yylval.t->data.type_float);
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return FLOAT;
}
{int_8} {
    yylval.t=treeNodeTokenInit(INT,yylineno);
    yylval.t->data.type_int=(unsigned)strtol(yytext,NULL,8);
    yylval.t->info=str_maker("INT: %u",yylval.t->data.type_int);
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return INT;
}
{int_16} {
    yylval.t=treeNodeTokenInit(INT,yylineno);
    yylval.t->data.type_int=(unsigned)strtol(yytext,NULL,16); 
    yylval.t->info=str_maker("INT: %u",yylval.t->data.type_int);
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return INT;
}
{int_10} {
    yylval.t=treeNodeTokenInit(INT,yylineno);
    yylval.t->data.type_int=(unsigned)strtol(yytext,NULL,10);
    yylval.t->info=str_maker("INT: %u",yylval.t->data.type_int);
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return INT;
}
{ID} {
    yylval.t=treeNodeTokenInit(INT,yylineno);
    yylval.t->data.type_name=str_maker("%s",yytext);
    yylval.t->info=str_maker("ID: %s",yytext);
    LOG_ON_FLEX("%s\n",yylval.t->info);
    return ID;
}
\. {RET(DOT);}

. {
    #ifdef LESS
    printf("Error type A at Line %d",yylineno);putchar('\n');
    #else
    printf("Error type A at Line %d: Mysterious characters \'%s\'.\n",
    yylineno,yytext);
    #endif
    flex_error=1;
}
%%
static inline void clear_note(char c1){
    for(;;){
        int ch=input();
        LOG_FLEX_NATIVE("%c",ch);
        while(ch&&ch!=c1){
            ch=input();
            if((ch!='\n'||ch!=c1)&&ch!=0) LOG_FLEX_NATIVE("%c",ch,ch);
        }
        if(c1=='\n') return;
        if(!ch){
            LOG_FLEX_NATIVE("\n");
            printf("Error type A at Line %d: Incomplete Comment.\n",yylineno);
            flex_error=1;
            return;
        }
        ch=input();
        if(ch=='/') {
            LOG_FLEX_NATIVE("%c",ch);
            return;
        }
        unput(ch);
    } 
}
